package com.ztrue.framework.context;

import com.ztrue.framework.core.domain.IAggregateRoot;
import com.ztrue.framework.core.domain.IAggregateRootCache;
import com.ztrue.framework.core.event.IDomainEvent;
import com.ztrue.framework.exception.InvalidOperationException;
import com.ztrue.framework.handler.IHandlerDefinitionRegistry;
import com.ztrue.framework.handler.definition.EventHandlerMethodDefinition;
import com.ztrue.framework.handler.definition.IHandlerDefinition;
import com.ztrue.common.log.Logger;

/**
 * 表示一个默认的领域事件内部处理器提供者
 *
 * @author zhangw
 * @date 2016/12/3 18:26
 * @version: 1.0
 */
public class DefaultAggregateRootInternalHandlerProvider implements IAggregateRootInternalHandlerProvider {
    private static final Logger logger = Logger.getLogger(DefaultAggregateRootInternalHandlerProvider.class);
    private final IHandlerDefinitionRegistry handlerDefinitionRegistry;
    private IAggregateRootCache aggregateRootCache;

    public DefaultAggregateRootInternalHandlerProvider(IHandlerDefinitionRegistry handlerDefinitionRegistry, IAggregateRootCache aggregateRootCache) {
        this.handlerDefinitionRegistry = handlerDefinitionRegistry;
        this.aggregateRootCache = aggregateRootCache;
    }

    /**
     * 处理
     *
     * @param aggregateRoot 领域对象
     * @param domainEvent   领域事件
     */
    @Override
    public void handle(IAggregateRoot aggregateRoot, IDomainEvent domainEvent) {
        String[] handlerNames = this.handlerDefinitionRegistry.getHandlerNameByTargetTypeAndHandlerType(domainEvent.getClass(), aggregateRoot.getClass());
        for (String handlerName : handlerNames) {
            doHandle(handlerName, aggregateRoot, domainEvent);
        }
        aggregateRootCache.set(aggregateRoot);
    }

    /**
     * 开始处理
     *
     * @param handlerName   处理器名称
     * @param aggregateRoot 领域对象
     * @param domainEvent   领域事件
     */
    private void doHandle(String handlerName, IAggregateRoot aggregateRoot, IDomainEvent domainEvent) {
        try {
            IHandlerDefinition handlerDefinition = handlerDefinitionRegistry.getHandlerDefinition(handlerName);
            if (EventHandlerMethodDefinition.class.isAssignableFrom(handlerDefinition.getClass())) {
                ((EventHandlerMethodDefinition) handlerDefinition).getExecMethod().invoke(aggregateRoot, domainEvent);
            }
        } catch (Exception e) {
            logger.error("无法访问领域对象[" + aggregateRoot.getClass().getName() + "]的方法[" + handlerName + "]", e);
            throw new InvalidOperationException("无法访问领域对象[" + aggregateRoot.getClass().getName() + "]的方法[" + handlerName + "]", e);
        }
    }
}
